/*-------------------------------------------------------------------------
 *
 * fallback.h
 *    对没有自旋锁和/或原子支持的平台的后备。比本地原子支持要慢，
 *    但不会慢到无法使用。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/port/atomics/fallback.h
 *
 *-------------------------------------------------------------------------
 */

/* 故意没有包含保护，应该仅由 atomics.h 包含 */
#ifndef INSIDE_ATOMICS_H
#	error "should be included via atomics.h"
#endif

#ifndef pg_memory_barrier_impl
/*
 * 如果我们没有针对该架构的内存屏障实现，我们
 * 将退回到获取和释放自旋锁。这可能会反过来
 * 退回到基于信号量的自旋锁实现，这将会
 * 非常慢。
 *
 * 并不是显而易见每个可能的合法自旋锁
 * 获取和释放的实现等同于完整的内存屏障。
 * 例如，我不确定 Itanium 的 acq 和 rel 是否加起来
 * 等同于一个完整的屏障。但是我们所有的实际实现
 * 在这方面似乎都正常。
 */
#define PG_HAVE_MEMORY_BARRIER_EMULATION

extern void pg_spinlock_barrier(void);
#define pg_memory_barrier_impl pg_spinlock_barrier
#endif

#ifndef pg_compiler_barrier_impl
/*
 * 如果编译器/架构组合不提供编译器屏障， 
 * 则提供一个后备方案。后备方案仅由调用一个外部定义的函数组成。 
 * 这应该可以保证编译器屏障语义，除了那些进行翻译单元/全局优化的编译器— 
 * 那些编译器最好提供一个实际的编译器屏障。
 *
 * 一个原生的编译器屏障肯定比这个快得多...
 */
#define PG_HAVE_COMPILER_BARRIER_EMULATION
extern void pg_extern_compiler_barrier(void);
#define pg_compiler_barrier_impl pg_extern_compiler_barrier
#endif


/*
 * 如果我们为此平台提供原子操作的实现， 
 * 退而求其次使用一个自旋锁来保护内部状态。可能该自旋锁的实现内部使用信号量...
 *
 * 在这里我们必须小心，因为不能保证原子变量在每个进程中映射到相同的地址（例如动态共享内存段）。 
 * 我们不能仅仅对地址进行哈希并使用它来映射到自旋锁。 
 * 而是要在原子变量初始化时分配一个自旋锁。
 */
#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && !defined(PG_HAVE_ATOMIC_U32_SUPPORT)

#define PG_HAVE_ATOMIC_FLAG_SIMULATION
#define PG_HAVE_ATOMIC_FLAG_SUPPORT

typedef struct pg_atomic_flag
{
	/*
	 * 为了避免循环包含，我们不能在这里使用s_lock作为类型。 
	 * 而是为所有自旋锁类型保留足够的空间。某些平台可能只需要一个字节而不是4字节，但这并不算浪费太多。
	 */
#if defined(__hppa) || defined(__hppa__)	/* HP PA-RISC, GCC 和 HP 编译器 */
	int			sema[4];
#else
	int			sema;
#endif
	volatile bool value;
} pg_atomic_flag;

#endif /* PG_HAVE_ATOMIC_FLAG_SUPPORT */

#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT)

#define PG_HAVE_ATOMIC_U32_SIMULATION

#define PG_HAVE_ATOMIC_U32_SUPPORT
typedef struct pg_atomic_uint32
{
	/* 请检查上述 pg_atomic_flag 的定义以获取解释 */
#if defined(__hppa) || defined(__hppa__)	/* HP PA-RISC, GCC 和 HP 编译器 */
	int			sema[4];
#else
	int			sema;
#endif
	volatile uint32 value;
} pg_atomic_uint32;

#endif /* PG_HAVE_ATOMIC_U32_SUPPORT */

#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT)

#define PG_HAVE_ATOMIC_U64_SIMULATION

#define PG_HAVE_ATOMIC_U64_SUPPORT
typedef struct pg_atomic_uint64
{
	/* 请检查上述 pg_atomic_flag 的定义以获取解释 */
#if defined(__hppa) || defined(__hppa__)	/* HP PA-RISC, GCC 和 HP 编译器 */
	int			sema[4];
#else
	int			sema;
#endif
	volatile uint64 value;
} pg_atomic_uint64;

#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */

#ifdef PG_HAVE_ATOMIC_FLAG_SIMULATION

#define PG_HAVE_ATOMIC_INIT_FLAG
extern void pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr);

#define PG_HAVE_ATOMIC_TEST_SET_FLAG
extern bool pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr);

#define PG_HAVE_ATOMIC_CLEAR_FLAG
extern void pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr);

#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
extern bool pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr);

#endif /* PG_HAVE_ATOMIC_FLAG_SIMULATION */

#ifdef PG_HAVE_ATOMIC_U32_SIMULATION

#define PG_HAVE_ATOMIC_INIT_U32
extern void pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_);

#define PG_HAVE_ATOMIC_WRITE_U32
extern void pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val);

#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
extern bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
												uint32 *expected, uint32 newval);

#define PG_HAVE_ATOMIC_FETCH_ADD_U32
extern uint32 pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_);

#endif /* PG_HAVE_ATOMIC_U32_SIMULATION */


#ifdef PG_HAVE_ATOMIC_U64_SIMULATION

#define PG_HAVE_ATOMIC_INIT_U64
extern void pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_);

#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
extern bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
												uint64 *expected, uint64 newval);

#define PG_HAVE_ATOMIC_FETCH_ADD_U64
extern uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_);

#endif /* PG_HAVE_ATOMIC_U64_SIMULATION */
